package com.yk.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yk.api.system.dto.AlarmDTO;
import com.yk.api.system.dto.AlarmHistoryDTO;
import com.yk.api.system.dto.ConditionDTO;
import com.yk.api.system.dto.DeviceDTO;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.utils.DateUtils;
import com.yk.common.excel.utils.ExcelUtil;
import com.yk.system.convert.AlarmConvert;
import com.yk.system.convert.AlarmHistoryConvert;
import com.yk.system.entity.Alarm;
import com.yk.system.entity.AlarmHistory;
import com.yk.system.entity.Device;
import com.yk.system.entity.Variable;
import com.yk.system.service.AlarmHistoryService;
import com.yk.system.service.AlarmService;
import com.yk.system.service.DeviceService;
import com.yk.system.service.VariableService;
import com.yk.system.vo.AlarmDeviceStatisticsChartsVO;
import com.yk.system.vo.AlarmDeviceStatisticsVO;
import com.yk.system.vo.AlarmGroupStatisticsVO;
import com.yk.system.vo.AlarmStatisticsVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 报警历史表 yk-system
 *
 * @author lmx
 * @since 2023-11-21
 */
@Api(tags = "报警历史表")
@RestController
@RequestMapping("/alarmHistory")
@RequiredArgsConstructor
public class AlarmHistoryController {

    private final AlarmHistoryService alarmHistoryService;
    private final DeviceService deviceService;
    private final VariableService variableService;
    private final AlarmService alarmService;
    private final AlarmConvert alarmConvert;
    private final AlarmHistoryConvert alarmHistoryConvert;

    @GetMapping("/getById/{id}")
    @ApiOperation("报警历史表-查询单个")
    public Result<AlarmHistory> getById(@PathVariable(value = "id") Long id) {
        return Result.data(alarmHistoryService.getById(id));
    }

    @PostMapping("/save")
    @ApiOperation("报警历史表-新增")
    public Result<Boolean> save(@RequestBody @Validated AlarmHistoryDTO dto) {
        return Result.data(alarmHistoryService.save(alarmHistoryConvert.dto2Entity(dto)));
    }

    @PostMapping("/update")
    @ApiOperation("报警历史表-修改")
    public Result<Boolean> updateById(@RequestBody @Validated AlarmHistoryDTO dto) {
        return Result.data(alarmHistoryService.updateById(alarmHistoryConvert.dto2Entity(dto)));
    }

    @GetMapping("/deleteById/{id}")
    @ApiOperation("报警历史表-删除")
    public Result<Boolean> deleteById(@PathVariable(value = "id") Long id) {
        return Result.data(alarmHistoryService.removeById(id));
    }

    @GetMapping("/getOldTime")
    @ApiOperation("报警历史表-查询最久一条数据的时间")
    public Result<Date> deleteById() {
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        List<DeviceDTO> dtoList = deviceService.selectRole2Device();
        if (CollUtil.isEmpty(dtoList)) {
            return Result.data(null);
        }
        List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
        lambda.in(AlarmHistory::getDeviceId, ids);
        lambda.orderByAsc(AlarmHistory::getAlarmAt);
        lambda.last("limit 1");
        AlarmHistory one = alarmHistoryService.getOne(lambda);
        if (Objects.isNull(one)) {
            return Result.data(null);
        }
        return Result.data(one.getAlarmAt());
    }

    @PostMapping("/list")
    @ApiOperation("报警历史表-查询列表")
    public Result<List<AlarmHistory>> list(@RequestBody AlarmHistoryDTO param) {
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        if (Objects.isNull(param.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isEmpty(dtoList)) {
                return Result.data(CollUtil.newArrayList());
            }
            List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
            lambda.in(AlarmHistory::getDeviceId, ids);
        }
        buildCondition(lambda, param);
        return Result.data(alarmHistoryService.list(lambda));
    }

    @PostMapping("/page")
    @ApiOperation("报警历史表-分页查询")
    public PageResult<AlarmHistoryDTO> page(@RequestBody BasePageQuery<AlarmHistoryDTO> pageParam) {
        AlarmHistoryDTO param = pageParam.getParam();
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        if (StrUtil.isNotEmpty(param.getInformType())) {
            List<Alarm> list = alarmService.getByInformType(param.getInformType());
            if (CollUtil.isEmpty(list)) {
                return PageResult.success(CollUtil.newArrayList(), 0);
            }
            List<Long> ids = list.stream().map(Alarm::getId).collect(Collectors.toList());
            lambda.in(AlarmHistory::getAlarmId, ids);
        }
        if (Objects.isNull(param.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isEmpty(dtoList)) {
                return PageResult.success(CollUtil.newArrayList(), 0);
            }
            List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
            lambda.in(AlarmHistory::getDeviceId, ids);
        }
        buildCondition(lambda, param);
        IPage<AlarmHistoryDTO> page = alarmHistoryService.page(new Page<>(pageParam.getPageNum(), pageParam.getPageSize()), lambda).convert(alarmHistoryConvert::entity2Dto);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            page.getRecords().forEach(it -> {
                // 设备名称
                Device device = deviceService.getById(it.getDeviceId());
                if (Objects.nonNull(device)) {
                    it.setDeviceName(device.getDeviceName());
                }
                // 变量名称
                Variable variable = variableService.getById(it.getVariableId());
                if (Objects.nonNull(variable)) {
                    it.setVariableName(variable.getName());
                }
                // 触发条件
                Alarm alarm = alarmService.selectById(it.getAlarmId());
                if (Objects.nonNull(alarm)) {
                    AlarmDTO dto = alarmConvert.entity2Dto(alarm);
                    it.setRule(dto.getRule());
                }
            });
        }
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @PostMapping("/dealWithAlarmMessage")
    @ApiOperation("报警历史表-报警信息处理")
    public Result<Void> dealWithAlarmMessage(@RequestBody AlarmHistoryDTO param) {
        alarmHistoryService.dealWithAlarmMessage(param);
        return Result.ok();
    }

    @GetMapping("/statistics")
    @ApiOperation("报警历史表-统计")
    public Result<AlarmStatisticsVO> statistics() {
        Date date = new Date();
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        List<DeviceDTO> dtoList = deviceService.selectRole2Device();
        if (CollUtil.isEmpty(dtoList)) {
            return Result.data(new AlarmStatisticsVO(0, 0L, 0L, 0));
        }
        List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
        lambda.in(AlarmHistory::getDeviceId, ids);
        lambda.between(AlarmHistory::getAlarmAt, DateUtils.getDayStartTime(date), DateUtils.getDayEndTime(date));
        List<AlarmHistory> list = alarmHistoryService.list(lambda);
        AlarmStatisticsVO vo = new AlarmStatisticsVO();
        // 今日报警数
        vo.setTodayCount(list.size());
        // 今日报警中
        vo.setTodayAlarmCount(list.stream().filter(AlarmHistory::getAlarmState).count());
        // 今日已恢复
        vo.setTodayRecoverCount(list.stream().filter(it -> !it.getAlarmState()).count());
        // 本周报警数
        LambdaQueryWrapper<AlarmHistory> weekLambda = new QueryWrapper<AlarmHistory>().lambda();
        weekLambda.between(AlarmHistory::getAlarmAt, DateUtils.getWeeklyStartTime(date), DateUtils.getWeeklyEndTime(date));
        List<AlarmHistory> weekList = alarmHistoryService.list(lambda);
        vo.setWeekCount(weekList.size());
        return Result.data(vo);
    }

    @PostMapping("/statisticsByGroup")
    @ApiOperation("根据场景和时间范围统计")
    public Result<List<AlarmGroupStatisticsVO>> statisticsByGroup(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getGroupId())) {
            return Result.fail("场景id不能为空");
        }
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("开始时间和结束时间不能为空");
        }
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.statisticsByGroup(dto));
    }

    @PostMapping("/statisticsByDevice")
    @ApiOperation("根据设备按天统计")
    public Result<List<AlarmDeviceStatisticsVO>> statisticsByDevice(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getDeviceId())) {
            return Result.fail("设备id不能为空");
        }
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("开始时间和结束时间不能为空");
        }
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.statisticsByDevice(dto));
    }

    @PostMapping("/app/statisticsByDevice")
    @ApiOperation("小程序按天统计")
    public Result<List<AlarmDeviceStatisticsVO>> app2statisticsByDevice(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("时间不能为空");
        }
        getDeviceIds(dto);
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.app2statisticsByDevice(dto));
    }

    @PostMapping("/app/statisticsHourByDevice")
    @ApiOperation("小程序按小时统计")
    public Result<List<AlarmDeviceStatisticsVO>> statisticsHourByDevice(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("时间不能为空");
        }
        getDeviceIds(dto);
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.statisticsHourByDevice(dto));
    }

    @PostMapping("/app/statisticsByDevice2Charts")
    @ApiOperation("小程序统计饼图-统计设备")
    public Result<List<AlarmDeviceStatisticsChartsVO>> statisticsByDevice2Charts(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("时间不能为空");
        }
        getDeviceIds(dto);
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.statisticsByDevice2Charts(dto));
    }

    @PostMapping("/app/statisticsByDeviceId2Charts")
    @ApiOperation("小程序统计饼图-统计设备下变量")
    public Result<List<AlarmDeviceStatisticsChartsVO>> statisticsByDeviceId2Charts(@RequestBody AlarmHistoryDTO dto) {
        if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
            return Result.fail("时间不能为空");
        }
        Assert.notNull(dto.getDeviceId(), "设备id不能为空");
        dto.setStartTime(DateUtils.getDayStartTime(dto.getStartTime()));
        dto.setEndTime(DateUtils.getDayEndTime(dto.getEndTime()));
        return Result.data(alarmHistoryService.statisticsByDeviceId2Charts(dto));
    }

    @PostMapping("/countNum")
    @ApiOperation("小程序页面统计数")
    public Result<AlarmDeviceStatisticsChartsVO> countNum(@RequestBody AlarmHistoryDTO dto) {
        AlarmDeviceStatisticsChartsVO vo = new AlarmDeviceStatisticsChartsVO();
        vo.setCount(0);
        vo.setAlarmCount(0);
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        if (Objects.isNull(dto.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isEmpty(dtoList)) {
                return Result.data(vo);
            }
            List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
            lambda.in(AlarmHistory::getDeviceId, ids);
        }
        lambda.eq(Objects.nonNull(dto.getDeviceId()), AlarmHistory::getDeviceId, dto.getDeviceId());
        lambda.eq(Objects.nonNull(dto.getVariableId()), AlarmHistory::getVariableId, dto.getVariableId());
        lambda.eq(Objects.nonNull(dto.getAlarmState()), AlarmHistory::getAlarmState, dto.getAlarmState());
        lambda.between(Objects.nonNull(dto.getStartTime()), AlarmHistory::getAlarmAt, dto.getStartTime(), dto.getEndTime());
        List<AlarmHistory> list = alarmHistoryService.list(lambda);
        if (CollUtil.isNotEmpty(list)) {
            vo.setCount(list.size());
            long count = list.stream().filter(AlarmHistory::getAlarmState).count();
            vo.setAlarmCount((int) count);
            return Result.data(vo);
        }
        return Result.data(vo);
    }

    @ApiOperation("导出")
    @GetMapping("/export")
    public void export(HttpServletResponse response, AlarmHistoryDTO dto) {
        if (StrUtil.isEmpty(dto.getToken())) {
            return;
        }
        LambdaQueryWrapper<AlarmHistory> lambda = new QueryWrapper<AlarmHistory>().lambda();
        if (Objects.isNull(dto.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Token(dto.getToken());
            if (CollUtil.isNotEmpty(dtoList)) {
                List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
                lambda.in(AlarmHistory::getDeviceId, ids);
            }
        }
        buildCondition(lambda, dto);
        List<AlarmHistory> list = alarmHistoryService.list(lambda);
        List<AlarmHistoryDTO> dtoList = CollUtil.newArrayList();
        AtomicInteger index = new AtomicInteger(1);
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(it -> {
                AlarmHistoryDTO alarmHistoryDTO = alarmHistoryConvert.entity2Dto(it);
                alarmHistoryDTO.setIndex(index.getAndIncrement());
                // 状态
                Boolean alarmState = it.getAlarmState();
                if (Objects.nonNull(alarmState)) {
                    alarmHistoryDTO.setAlarmStateStr(alarmState ? "报警" : "正常");
                }
                // 设备名称
                Device device = deviceService.getById(it.getDeviceId());
                if (Objects.nonNull(device)) {
                    alarmHistoryDTO.setDeviceName(device.getDeviceName());
                }
                // 变量名称
                Variable variable = variableService.getById(it.getVariableId());
                if (Objects.nonNull(variable)) {
                    alarmHistoryDTO.setVariableName(variable.getName());
                }
                // 触发条件
                Alarm alarm = alarmService.getById(it.getAlarmId());
                if (Objects.nonNull(alarm)) {
                    AlarmDTO alarmDTO = alarmConvert.entity2Dto(alarm);
                    ConditionDTO rule = alarmDTO.getRule();
                    if (Objects.nonNull(rule)) {
                        alarmHistoryDTO.setRuleStr(ConditionDTO.getRuleStr(rule.getName(), rule.getValueA(), rule.getValueB()));
                    }
                }
                dtoList.add(alarmHistoryDTO);
            });
        }
        ExcelUtil.exportExcel(dtoList, "数据", "报警记录", AlarmHistoryDTO.class, response);
    }

    /**
     * 构造查询条件
     */
    private void buildCondition(LambdaQueryWrapper<AlarmHistory> lambda, AlarmHistoryDTO param) {
        if (Objects.nonNull(param)) {
            lambda.eq(Objects.nonNull(param.getDeviceId()), AlarmHistory::getDeviceId, param.getDeviceId());
            lambda.eq(Objects.nonNull(param.getVariableId()), AlarmHistory::getVariableId, param.getVariableId());
            lambda.eq(Objects.nonNull(param.getAlarmState()), AlarmHistory::getAlarmState, param.getAlarmState());
            lambda.eq(Objects.nonNull(param.getStatus()), AlarmHistory::getStatus, param.getStatus());
            lambda.between(Objects.nonNull(param.getStartTime()), AlarmHistory::getAlarmAt, param.getStartTime(), param.getEndTime());
        }
        lambda.orderByDesc(AlarmHistory::getAlarmAt);
    }

    /**
     * 获取deviceIDs
     */
    private void getDeviceIds(AlarmHistoryDTO dto) {
        if (Objects.nonNull(dto.getDeviceId())) {
            dto.setDeviceIdList(CollUtil.newArrayList(dto.getDeviceId()));
        } else {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isEmpty(dtoList)) {
                return;
            }
            List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
            dto.setDeviceIdList(ids);
        }
    }
}